/**
 * 判断某一年是否是闰年
 *
 * @param year 可以是一个date类型，也可以是一个int类型的年份，不传默认当前时间
 * @return Boolean 布尔值
 */
function isLeapYear(year) {
    if(year === undefined) year = new Date();
    if(year instanceof Date) year = year.getFullYear();
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
/**
 * 获取当天日期（格式：yyyy-mm-dd）
 *
 * @param
 * @return String 日期值
 * */
function getCurDate() {
	let date = new Date();
	let year = date.getFullYear();
	let month = date.getMonth() + 1;
	let day = date.getDate();
	if(month < 10)
		month = "0" + month;
	if(day < 10)
		day = "0" + day;
	let curDate = year + "-" + month + "-" + day;

	return curDate;
}
/**
 * 获取某一年某一月的总天数，没有任何参数时获取当前月份的
 *
 * @param date 日期
 * @param month 月份
 *
 * @return Number 总天数
 *
 * 方式一：$.getMonthDays();
 * 方式二：$.getMonthDays(new Date());
 * 方式三：$.getMonthDays(2013, 12);
 */
function getMonthDays(date, month) {
    let y, m;
    if(date == undefined) date = new Date();
    if(date instanceof Date) {
        y = date.getFullYear();
        m = date.getMonth();
    }else if(typeof date == 'number') {
        y = date;
        m = month-1;
    }
    let days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // 非闰年的一年中每个月份的天数
    //如果是闰年并且是2月
    if(m == 1 && isLeapYear(y)) return days[m]+1;
    return days[m];
}
/**
 * 将日期格式化成指定格式的字符串
 *
 * @param date 要格式化的日期，不传时默认当前时间，也可以是一个时间戳
 * @param fmt 目标字符串格式，支持的字符有：y,M,d,q,w,H,h,m,S，默认：yyyy-MM-dd HH:mm:ss
 *
 * @returns String 返回格式化后的日期字符串
 */
function formatDate(date, fmt) {
	date = date == undefined ? new Date() : new Date(date);
	date = typeof date == 'number' ? new Date(date) : date;
	fmt = fmt || 'yyyy-MM-dd HH:mm:ss';
	let obj =
		{
			'y': date.getFullYear(), // 年份，注意必须用getFullYear
			'M': date.getMonth() + 1, // 月份，注意是从0-11
			'd': date.getDate(), // 日期
			'q': Math.floor((date.getMonth() + 3) / 3), // 季度
			'w': date.getDay(), // 星期，注意是0-6
			'H': date.getHours(), // 24小时制
			'h': date.getHours() % 12 == 0 ? 12 : date.getHours() % 12, // 12小时制
			'm': date.getMinutes(), // 分钟
			's': date.getSeconds(), // 秒
			'S': date.getMilliseconds() // 毫秒
		};
	let week = ['天', '一', '二', '三', '四', '五', '六'];
	for(let i in obj) {
		fmt = fmt.replace(new RegExp(i+'+', 'g'), function(m)
		{
			let val = obj[i] + '';
			if(i == 'w') return (m.length > 2 ? '星期' : '周') + week[val];
			for(let j = 0, len = val.length; j < m.length - len; j++) val = '0' + val;
			return m.length == 1 ? val : val.substring(val.length - m.length);
		});
	}
	return fmt;
}
/**
 * 返回日期（相对于某一天的前后dayP天）
 *
 * @param dateP (某一个日期值)日期值
 * @param dayP 日期差值
 *
 * @return String 日期值
 * */
function setDateStrByDate(dateP, dayP) {
	let dd = new Date(dateP);
	dd.setDate(dd.getDate() + dayP);
	let y = dd.getFullYear();
	let m = dd.getMonth() + 1;
	let d = dd.getDate();

	if(m > 0 && m < 10)m = "0" + m;
	if(d > 0 && d < 10)d = "0" + d;

	let dr = y + "-" + m + "-" + d;
	return dr;
}
/**
 * 返回两个日期之间的差值
 *
 * @param date1 日期字符串1
 * @param date2 日期字符串2
 *
 * @return number 相差天数
 **/
function getDateDifference(date1, date2) {
	var minute = 1000 * 60;
	var hour = minute * 60;
	var day = hour * 24;

	var difference_millisecond = Math.abs(Date.parse(date1) - Date.parse(date2));	// 确保差值为正数
	var difference_day = difference_millisecond / day;	// 返回天数
	return difference_day;
}
/**
 * 计算多少分钟后的日期时间
 *
 * @param date 日期字符串
 * @param minute 分钟
 *
 * @return number 计算后的时间戳
 **/
function calcDatetime(date, minute) {
	date = date ? new Date(date) : new Date();
	return date.getTime() + minute * 60 * 1000;
}



/**
* 日期构造函数
**/
function calendarTool() {
	const d = new Date();
	this.year_limit_first = d.getFullYear(); // 往前的年份边界
	this.year_limit_last = d.getFullYear(); // 往后的年份边界
	this.year = null;	// 当年值
	this.month = null;	// 当月值
	this.days = null;	// 当月天数值
	this.row = 6;	// 行数
	this.col = 7;	// 列数
    this.monthLeft = false; // 点击上个月(用于确定月份到达边界时, 是否改变年份)
    this.monthRight = false;    // 点击下个月
    this.yearLeft = false;  // 点击上一年
    this.yearRight = false; // 点击下一年
    this.menuArr = [11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0];
    this.menuNameArr = ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"];
	this.weekNumOfFirstDay = 0;	// 当月1号表示的星期的某一天的数字
	this.weekNumOfLastDay = 0;	// 当月最后一天表示的星期的某一天的数字
	this.curMonthEveryDate = []; // 当月的每天日期全值
	this.curMonthEveryDay = []; // 当月的每天日期单号
	this.curMonthEveryDayDate = []; // 当月的每天日期单号、日期值
	this.allDates = []; // 展示的所有日期
	// 加载日期
	this.loadCurrentMonthDate(null);
}
/**
* 加载当月日期
*
* @param datev 日期参数
**/
calendarTool.prototype.loadCurrentMonthDate = function(datev) {
    datev = datev ? datev : getCurDate();
    let dateA = datev.split("-");
	let weekArr = ["日", "一", "二", "三", "四", "五", "六"];
	let d = new Date(dateA[0], parseInt(dateA[1])-1, dateA[2]);
	this.year = d.getFullYear();
	// 当月天数
    let curMonthDays = new Date(d.getFullYear(), (d.getMonth() + 1), 0).getDate();
    this.days = curMonthDays;

    let curMonthEveryDate = [], curMonthEveryDay = [], curMonthEveryDayDate = [];	// 当月的每天日期全值, 单号, 单号及全值
    for (let i = 0; i < curMonthDays; i++) {
    	let dateM = d.getMonth() + 1;
    	if(dateM < 10)dateM = "0" + dateM;
    	this.month = dateM;

    	let dateD = i + 1;
    	let dateD2 = i + 1;
    	if(dateD < 10)dateD = "0" + dateD;

    	curMonthEveryDate[i] = d.getFullYear() + "-" + dateM + "-" + dateD;
    	curMonthEveryDay[i] = dateD2;
    	curMonthEveryDayDate[i] = {
    		isCurrentMonth: true,
    		year: this.year,
    		month: this.month,
    		date: curMonthEveryDate[i],
    		day: curMonthEveryDay[i]
    	};
    }
    this.curMonthEveryDate = curMonthEveryDate;
    this.curMonthEveryDay = curMonthEveryDay;
    this.curMonthEveryDayDate = curMonthEveryDayDate;
    // 返回该月1号表示星期的某一天的数字, 用于在表格中的起始位置
    this.weekNumOfFirstDay = new Date(curMonthEveryDate[0]).getDay();
    this.weekNumOfLastDay = new Date(curMonthEveryDate[curMonthDays - 1]).getDay();
    // console.log("今年是：" + this.year + " 年");
    // console.log("现在是：" + this.month + " 月");
    // console.log(`${this.month} 月日历是：`, this.curMonthEveryDate, this.curMonthEveryDay);
    // console.log("这个月一共有：" + this.days + " 天");
    // console.log("这个月的 " + curMonthEveryDate[0] + " 是："+this.weekNumOfFirstDay + " , " + weekArr[this.weekNumOfFirstDay]);
    // console.log("这个月的 " + curMonthEveryDate[curMonthDays - 1] + " 是：" + this.weekNumOfLastDay + " , " + weekArr[this.weekNumOfLastDay]);

    // 填补空白日期
    const {before: fillBeforeDate} = this.fillDateOfNotCurMonth(curMonthEveryDay[0], curMonthEveryDate[0], this.weekNumOfFirstDay);
    const {after: fillAfterDate} = this.fillDateOfNotCurMonth(curMonthEveryDay[curMonthDays - 1], curMonthEveryDate[curMonthDays - 1], this.weekNumOfLastDay);
    this.allDates = fillBeforeDate.concat(curMonthEveryDayDate).concat(fillAfterDate);
    // console.log("填补前位：", fillBeforeDate)
    // console.log("填补后位：", fillAfterDate)
    // console.log("最终展示：", this.allDates)
};
/**
* 填补日历非当月空白区日期
*
* @param paramDay 一个日期单号, 用于对比判断区别算法
* @param paramDate 一个日期参数, 用于取相对于它的日期
* @param paramNum 一个整数值, 用于取相对于paramDate这个日期的paramNum天的日期
* @param type 返回值格式(0: 单日期号, 1: 全格式日期)
*
* @return resultDate 结果日期
**/
calendarTool.prototype.fillDateOfNotCurMonth = function(paramDay, paramDate, paramNum, type = 0) {
	let startIndexOfLastRow = this.days + this.weekNumOfFirstDay;	// 最后一行的起始下标
	let dd = null, result = {before: [], after: []};
	const getTheDate = function(num, type) {
		dd = new Date(paramDate);
		dd.setDate(dd.getDate() + num);

		if(type == 0) return dd.getDate();
		if(type == 1) {
			const year = dd.getFullYear();
			let month = dd.getMonth() + 1;
			let day = dd.getDate();
			month = month < 10 ? `0${month}` : month;
			day = day < 10 ? `0${day}` : day;

			return `${year}-${month}-${day}`;
		}
	};

	// 1号之前
	if(paramDay*1 == 1) {
		for(let i = 0; i < paramNum; i++) {
			const tempDate = getTheDate((paramNum - i) * (-1), 1);
			result.before.push({
				isCurrentMonth: false,
				day: getTheDate((paramNum - i) * (-1), 0),
				date: tempDate,
				month: tempDate.split("-")[1],
				year: tempDate.split("-")[0]
			});
		}
	}else {
		// 最后一天之后
		paramNum = this.row*this.col - startIndexOfLastRow;	// 最后一天之后需要填补的空白区数量

		for(let j = 0; j < paramNum; j++) {
			const tempDate = getTheDate(j+1, 1);
			result.after.push({
				isCurrentMonth: false,
				day: getTheDate(j+1, 0),
				date: tempDate,
				month: tempDate.split("-")[1],
				year: tempDate.split("-")[0]
			});
		}
	}
	return result;
};
/**
* 上一月
**/
calendarTool.prototype.showLastMonth = function(curM, todayDateText) {
    this.monthLeft = true;
    this.monthRight = false;
    this.month = this.menuArr[curM - 1];
    // console.log("show last month : "+this.month+"+1月, 今天是："+todayDateText+"号, 今年是："+this.year);
    this.handleMenuOperLeftRight(this.year, this.month, todayDateText, 0);
};

/**
* 下一月
**/
calendarTool.prototype.showNextMonth = function(curM, todayDateText) {
    this.monthRight = true;
    this.monthLeft = false;
    this.month = this.menuArr[curM + 1];
    // console.log("show next month : "+this.month+"+1月, 今天是："+todayDateText+"号, 今年是："+this.year);
    this.handleMenuOperLeftRight(this.year, this.month, todayDateText, 0);
};
/**
* 处理菜单操作(上/下 年/月)
*
* 0、校验是否到达年份列表边界
* 1、否：修改 年份/月份标题 的 显示/隐藏值
* 2、否：修改 年份/月份 菜单列表的样式
* 3、否：重新加载日历
*
* @param yearv 年份
* @param monthv 月份
* @param dayv 日期(不存在则为1号)
* @param operFrom 操作来源(0:上下月份, 1:上下年)
**/
calendarTool.prototype.handleMenuOperLeftRight = function(yearv, monthv, dayv, operFrom) {
	// console.log("yearv : ", yearv);
	// console.log("monthv : ", monthv);
	// console.log("year_limit_first : ", this.year_limit_first);
	// console.log("year_limit_last : ", this.year_limit_last);
	// console.log("monthLeft : ", this.monthLeft);
	// console.log("monthRight : ", this.monthRight);
	let changeDate = null, monthDays = null, monthStr = null;
    switch(operFrom) {
        case 0:
            monthStr = (this.month+1) < 10 ? ("0"+(this.month+1)) : (this.month+1);
            // 获取某一年某一月的总天数
            monthDays = getMonthDays(this.year, this.month+1);

            // 月份右边界
            if(monthv == 0 && this.monthRight) {
                // 下一年
                this.year = yearv + 1;
            }
            // 月份左边界
            if(monthv == 11 && this.monthLeft) {
                // 上一年
                this.year = yearv - 1;
            }
            // 当年月份
            if(monthv > 0 && monthv < 11) {
                // 当前年
            }
            break;
    }

    // 确定有效日期
    if(monthDays > dayv || monthDays == dayv) {
        changeDate = this.year + "-" + monthStr + "-" + dayv;
    }else {
        dayv = "01";
        changeDate = this.year + "-" + monthStr + "-" + dayv;
    }
    // console.log("changeDate ---------------- : ", changeDate)
    // 重新加载日期
    this.loadCurrentMonthDate(changeDate);
};
// 获取当前日期
calendarTool.prototype.getCurrentDate = function() {
	return getCurDate();
};
// 获取格式化后的日期
calendarTool.prototype.getFormatDate = function(date, fmt) {
	return formatDate(date, fmt);
};
// 获取计算后的日期
calendarTool.prototype.getDateByDate = function(date, day) {
	return setDateStrByDate(date, day);
};
// 获取日期差值
calendarTool.prototype.getDateDiff = function(date1, date2) {
	return getDateDifference(date1, date2);
};
// 获取多少分钟后的日期时间值
calendarTool.prototype.getDatetimeAfterSomeDatetime = function(date, minute) {
	const datetime = calcDatetime(date, minute);
	return this.getFormatDate(datetime, "yyyy-MM-dd HH:mm:ss");
};



calendarTool.prototype.test = function() {
	console.log("days : ", this.days)
}

const calendarObj = new calendarTool();
export default calendarObj;